use super::{GenColumn, GenIndex};
use crate::{
    error::{Error, Result},
    JsonMap,
};
use sea_orm::{DynIden, QueryResult};
use sea_query::{Alias, IntoIden, IntoTableRef, SimpleExpr};
use serde::Deserialize;
use std::collections::HashMap;

/// 序列化的GenTable, 方便定义数据
#[derive(Debug, Deserialize, Clone)]
#[allow(dead_code, unused)]
pub struct GenTableSerde {
    name: String,
    table_name: Option<String>,
    schema: Option<String>,
    columns: Vec<GenColumn>,
    #[serde(default)]
    indexs: Vec<GenIndex>,
}

impl Into<GenTable> for GenTableSerde {
    fn into(self) -> GenTable {
        GenTable::new(self.name, self.columns)
            .set_table_name(self.table_name)
            .set_schema(self.schema)
    }
}

#[derive(Debug, Clone)]
#[allow(dead_code, unused)]
pub struct GenTable {
    name: String,
    schema: Option<String>,
    /// 表的名字, 未定义时，使用name
    table_name: Option<String>,
    /// 标得注释
    table_comment: Option<String>,
    /// 只考虑单个id的表格
    pk: String,
    columns: HashMap<String, GenColumn>,
    indexs: Vec<GenIndex>,
}

impl IntoTableRef for &GenTable {
    fn into_table_ref(self) -> sea_query::TableRef {
        let table_name = self.table_name.as_ref().unwrap_or(&self.name);
        if let Some(schema) = &self.schema {
            sea_query::TableRef::SchemaTable(
                Alias::new(schema).into_iden(),
                Alias::new(table_name).into_iden(),
            )
        } else {
            sea_query::TableRef::Table(Alias::new(table_name).into_iden())
        }
    }
}

#[allow(dead_code, unused)]
impl GenTable {
    pub fn new<S: Into<String>>(name: S, columns: Vec<GenColumn>) -> Self {
        assert!(columns.len() > 0);
        let mut cols = HashMap::new();
        let mut def_pk = false;
        let mut pk = columns.first().unwrap().name().to_owned();
        for col in columns {
            if col.is_pk {
                def_pk = true;
                pk = col.name().to_owned();
            } else if !def_pk && col.name.eq("id") {
                pk = col.name().to_owned();
            }
            cols.insert(col.name.clone(), col);
        }
        Self {
            name: name.into(),
            schema: None,
            table_name: None,
            table_comment: None,
            columns: cols,
            indexs: vec![],
            pk,
        }
    }

    pub fn get_column(&self, name: &str) -> Option<&GenColumn> {
        self.columns.get(name)
    }

    pub fn coloumns_map(
        &self,
        columns: Option<Vec<String>>,
    ) -> Result<HashMap<String, &GenColumn>> {
        let mut cols: HashMap<String, &GenColumn> = HashMap::new();
        if let Some(columns) = columns {
            for col in columns {
                if let Some(v) = self.columns.get(&col) {
                    cols.insert(col, v);
                } else {
                    return Err(Error::UnknownColumn(col));
                }
            }
        } else {
            self.columns.iter().for_each(|f| {
                cols.insert(f.0.to_owned(), f.1);
            })
        }
        Ok(cols)
    }

    pub fn map_result(&self, result: &QueryResult) -> JsonMap {
        let mut map = serde_json::Map::new();
        self.columns.iter().for_each(|f| {
            if !f.1.is_hide {
                map.insert(f.0.clone(), f.1.try_get_value(result).unwrap());
            }
        });
        map
    }

    pub fn columns(&self) -> &HashMap<String, GenColumn> {
        &self.columns
    }

    /// 主键, 默认单键
    pub fn pk(&self) -> &GenColumn {
        self.get_column(&self.pk).unwrap()
    }

    pub fn set_schema(mut self, schema: Option<String>) -> Self {
        self.schema = schema;
        self
    }

    pub fn set_table_name(mut self, table_name: Option<String>) -> Self {
        self.table_name = table_name;
        self
    }

    pub fn set_table_comment(mut self, table_comment: Option<String>) -> Self {
        self.table_comment = table_comment;
        self
    }
}

#[allow(dead_code, unused)]
impl GenTable {
    /// 创建表格的statment
    pub fn table_create_statement(&self) -> sea_query::TableCreateStatement {
        let mut table_sql = sea_query::Table::create();
        table_sql.table(self).if_not_exists();
        if let Some(comment) = &self.table_comment {
            table_sql.comment(comment);
        }
        let mut has_primary_index = false;
        for index in &self.indexs {
            if index.is_primary() {
                has_primary_index = true
            }
            table_sql.index(&mut index.index());
        }
        let mut cols = self.columns.iter().map(|f| f.1).collect::<Vec<_>>();
        cols.sort_by_key(|f| f.sort);
        cols.iter()
            .map(|f| (f.column_def(), f.is_pk))
            .for_each(|(mut f, is_pk)| {
                if !has_primary_index && is_pk {
                    f.primary_key();
                }
                table_sql.col(&mut f);
            });
        table_sql
    }

    /// 返回查找数量的sql
    pub fn count(&self) -> sea_query::SelectStatement {
        let mut state = sea_query::Query::select();
        state.from(self);
        state.expr_as(self.pk().expr().count(), Alias::new("count"));
        state
    }

    pub fn select(&self) -> sea_query::SelectStatement {
        let mut state = sea_query::Query::select();
        state.from(self);
        self.columns
            .iter()
            .filter(|c| !c.1.is_hide)
            .for_each(|(_, f)| {
                state.expr_as(f.expr(), Alias::new(&f.name));
            });
        state
    }

    pub fn select_by_id<V>(&self, id: V) -> sea_query::SelectStatement
    where
        V: Into<SimpleExpr>,
    {
        let mut state = sea_query::Query::select();
        state.from(self);
        self.columns
            .iter()
            .filter(|c| !c.1.is_hide)
            .for_each(|(_, f)| {
                state.expr_as(f.expr(), Alias::new(&f.name));
            });
        state.and_where(self.pk().expr().eq(id));
        state
    }

    pub fn insert(&self, data: &JsonMap) -> sea_query::InsertStatement {
        let mut state = sea_query::Query::insert();
        state.into_table(self);
        state.or_default_values();

        let mut cols: Vec<DynIden> = vec![];
        let mut vals: Vec<SimpleExpr> = vec![];

        for (k, col) in self.columns() {
            if col.is_increment {
                continue;
            }
            // 主键优先使用默认生成的值
            if col.is_pk || k == &self.pk {
                if let Some(s) = col.default_value_expr() {
                    cols.push(col.iden());
                    vals.push(s);
                    continue;
                }
            };
            // 保护的字段
            if false {
                if let Some(s) = col.default_value_expr() {
                    cols.push(col.iden());
                    vals.push(s);
                    continue;
                }
            };
            match (data.get(k), col.default_value_expr()) {
                (None, None) => {
                    if col.is_required {
                        todo!()
                    }
                }
                // 使用默认值
                (None, Some(def)) => {
                    cols.push(col.iden());
                    vals.push(def)
                }
                (Some(v), _) => {
                    cols.push(col.iden());
                    vals.push(col.type_().expr_of(v).unwrap())
                }
            }
        }
        state.columns(cols);
        state.values(vals);
        state.returning_all();
        state
    }

    pub fn update_by_id<V>(&self, id: V, data: &JsonMap) -> sea_query::UpdateStatement
    where
        V: Into<SimpleExpr>,
    {
        let mut state = sea_query::query::UpdateStatement::new();
        state.table(self);
        for (k, col) in self.columns() {
            // 跳过主键
            if col.is_pk || col.is_increment || k == &self.pk {
                continue;
            }
            // 为保护字段
            if false {
                // 动态更新的字段
                if let Some(val) = col.update_value_expr() {
                    state.value(col.iden(), val);
                }
                continue;
            }
            if let Some(value) = data.get(k) {
                state.value(col.iden(), col.get_value_expr_from(value).unwrap());
            } else {
                // 动态更新的字段
                if let Some(val) = col.update_value_expr() {
                    state.value(col.iden(), val);
                }
            }
        }
        state.and_where(self.pk().expr().eq(id));
        state.returning_all();
        state
    }

    pub fn delete_by_id<V>(&self, id: V) -> sea_query::DeleteStatement
    where
        V: Into<SimpleExpr>,
    {
        let mut state = sea_query::query::DeleteStatement::new();
        state.from_table(self);
        state.and_where(self.pk().expr().eq(id));
        state.returning_all();
        state
    }
}
